﻿using System;
using System.Collections.Generic;
using System.Linq;
namespace HB.Expand
{

    /// <summary>
    /// 32和 64位的位运算，将多个0或1存为一个int或long，可用于权限管理值
    /// </summary>
    public static class CheckBits
    {
        static void CheckInput(int[] bitindex, int max)
        {
            if (bitindex.Count(zz => zz > max) > 0) { throw new System.Exception($"索引范围是0-{max.ToString()}"); }
        }
        /// <summary>
        /// 设置指定索引的bit为0
        /// </summary>
        /// <param name="j"></param>
        /// <param name="bitindex">0-7</param>
        /// <returns></returns>
        public static byte UnSetBit(this byte j, params int[] bitindex)
        {
            CheckInput(bitindex, 7);
            int i = j;
            foreach (int offset in bitindex)
            {
                if (offset < 8)
                {
                    int jt = ~(1 << offset);
                    i = i & jt;
                }
            }
            return (byte)i;
        }
        /// <summary>
        /// 设置指定索引的bit为0
        /// </summary>
        /// <param name="j"></param>
        /// <param name="bitindex">0-15</param>
        /// <returns></returns>
        public static ushort UnSetBit(this ushort j, params int[] bitindex)
        {
            CheckInput(bitindex, 15);
            int i = j;
            foreach (int offset in bitindex)
            {
                if (offset < 16)
                {
                    int jt = ~(1 << offset);
                    i = i & jt;
                }
            }
            return (ushort)i;
        }
        /// <summary>
        /// 设置指定索引的bit为0
        /// </summary>
        /// <param name="j"></param>
        /// <param name="bitindex">0-31</param>
        /// <returns></returns>
        public static int UnSetBit(this int j, params int[] bitindex)
        {
            CheckInput(bitindex, 31);
            int i = j;
            foreach (int offset in bitindex)
            {
                if (offset < 32)
                {
                    int jt = ~(1 << offset);
                    i = i & jt;
                }
            }
            return i;
        }
        /// <summary>
        /// 设置指定索引的bit为0
        /// </summary>
        /// <param name="j"></param>
        /// <param name="bitindex">0-63</param>
        /// <returns></returns>
        public static long UnSetBit(this long j, params int[] bitindex)
        {
            CheckInput(bitindex, 63);
            long i = j;
            foreach (int offset in bitindex)
            {
                if (offset < 64)
                {
                    long jt = ~(1L << offset);
                    i = i & jt;
                }
            }
            return i;
        }
        /// <summary>
        /// 设置指定索引的bit为1
        /// </summary>
        /// <param name="j"></param>
        /// <param name="bitindex">0-7</param>
        /// <returns></returns>
        public static byte SetBit(this byte j, params int[] bitindex)
        {
            CheckInput(bitindex, 7);
            int i = j;
            foreach (int offset in bitindex)
            {
                if (offset < 8)
                {
                    int jt = 1 << offset;
                    i = i | jt;

                }
            }
            return (byte)i;
        }
        /// <summary>
        /// 设置指定索引的bit为1
        /// </summary>
        /// <param name="j"></param>
        /// <param name="bitindex">0-15</param>
        /// <returns></returns>
        public static ushort SetBit(this ushort j, params int[] bitindex)
        {
            CheckInput(bitindex, 15);
            int i = j;
            foreach (int offset in bitindex)
            {
                if (offset < 16)
                {
                    int jt = 1 << offset;
                    i = i | jt;
                }
            }
            return (ushort)i;
        }
        /// <summary>
        /// 设置指定索引的bit为1
        /// </summary>
        /// <param name="j"></param>
        /// <param name="bitindex">0-31</param>
        /// <returns></returns>
        public static int SetBit(this int j, params int[] bitindex)
        {
            CheckInput(bitindex, 31);
            int i = j;
            foreach (int offset in bitindex)
            {
                if (offset < 32)
                {
                    int jt = 1 << offset;
                    i = i | jt;
                }
            }
            return i;
        }
        /// <summary>
        /// 设置指定索引的bit为1
        /// </summary>
        /// <param name="j"></param>
        /// <param name="bitindex">0-63</param>
        /// <returns></returns>
        public static long SetBit(this long j, params int[] bitindex)
        {
            CheckInput(bitindex, 63);
            long i = j;
            foreach (int offset in bitindex)
            {
                if (offset < 64)
                {
                    long jt = 1L << offset;
                    i = i | jt;
                }
            }
            return i;
        }
        /// <summary>
        /// 检查输入的索引对应值是否均为1
        /// </summary>
        /// <param name="data"></param>
        /// <param name="bitindex">0-7</param>
        /// <returns></returns>
        public static bool CheckBit(this byte data, params int[] bitindex)
        {
            CheckInput(bitindex, 7);
            bool result = true;
            foreach (int offset in bitindex)
            {
                if (offset < 8)
                {
                    int stand = 1 << offset;
                    int res = stand & data;
                    if (res == 0) { result = false; break; }
                }
            }
            return result;
        }
        /// <summary>
        /// 检查输入的索引对应值是否均为1
        /// </summary>
        /// <param name="data"></param>
        /// <param name="bitindex">0-15</param>
        /// <returns></returns>
        public static bool CheckBit(this ushort data, params int[] bitindex)
        {
            CheckInput(bitindex, 15);
            bool result = true;
            foreach (int offset in bitindex)
            {
                if (offset < 16)
                {
                    int stand = 1 << offset;
                    int res = stand & data;
                    if (res == 0) { result = false; break; }
                }
            }
            return result;
        }
        /// <summary>
        /// 检查输入的索引对应值是否均为1
        /// </summary>
        /// <param name="data"></param>
        /// <param name="bitindex">0-31</param>
        /// <returns></returns>
        public static bool CheckBit(this int data, params int[] bitindex)
        {
            CheckInput(bitindex, 31);
            bool result = true;
            foreach (int offset in bitindex)
            {
                if (offset < 32)
                {
                    int stand = 1 << offset;
                    int res = stand & data;
                    if (res == 0) { result = false; break; }
                }
            }
            return result;
        }
        /// <summary>
        /// 检查输入的索引对应值是否均为1
        /// </summary>
        /// <param name="data"></param>
        /// <param name="bitindex">0-63</param>
        /// <returns></returns>
        public static bool CheckBit(this long data, params int[] bitindex)
        {
            CheckInput(bitindex, 63);
            bool result = true;
            foreach (int offset in bitindex)
            {
                if (offset < 64)
                {
                    long stand = 1L << offset;
                    long res = stand & data;
                    if (res == 0) { result = false; break; }
                }
            }
            return result;
        }
        /// <summary>
        /// 检查输入的索引对应值是否含有1
        /// </summary>
        /// <param name="data"></param>
        /// <param name="bitindex">0-7</param>
        /// <returns></returns>
        public static bool CheckBitAny(this byte data, params int[] bitindex)
        {
            CheckInput(bitindex, 7);
            bool result = false;
            foreach (int offset in bitindex)
            {
                if (offset < 8)
                {
                    int stand = 1 << offset;
                    int res = stand & data;
                    if (res != 0) { result = true; break; }
                }
            }
            return result;
        }
        /// <summary>
        /// 检查输入的索引对应值是否含有1
        /// </summary>
        /// <param name="data"></param>
        /// <param name="bitindex">0-15</param>
        /// <returns></returns>
        public static bool CheckBitAny(this ushort data, params int[] bitindex)
        {
            CheckInput(bitindex, 15);
            bool result = false;
            foreach (int offset in bitindex)
            {
                if (offset < 16)
                {
                    int stand = 1 << offset;
                    int res = stand & data;
                    if (res != 0) { result = true; break; }
                }
            }
            return result;
        }
        /// <summary>
        /// 检查输入的索引对应值是否含有1
        /// </summary>
        /// <param name="data"></param>
        /// <param name="bitindex">0-31</param>
        /// <returns></returns>
        public static bool CheckBitAny(this int data, params int[] bitindex)
        {
            CheckInput(bitindex, 31);
            bool result = false;
            foreach (int offset in bitindex)
            {
                if (offset < 32)
                {
                    int stand = 1 << offset;
                    int res = stand & data;
                    if (res != 0) { result = true; break; }
                }
            }
            return result;
        }
        /// <summary>
        /// 检查输入的索引对应值是否含有1
        /// </summary>
        /// <param name="data"></param>
        /// <param name="bitindex">0-64</param>
        /// <returns></returns>
        public static bool CheckBitAny(this long data, params int[] bitindex)
        {
            CheckInput(bitindex, 63);
            bool result = false;
            foreach (int offset in bitindex)
            {
                if (offset < 64)
                {
                    long stand = 1L << offset;
                    long res = stand & data;
                    if (res != 0) { result = true; break; }
                }
            }
            return result;
        }
        /// <summary>
        /// 获取bit为1 的所有索引值
        /// </summary>
        /// <param name="j"></param>
        /// <returns></returns>
        public static List<byte> GetBits(this byte j)
        {
            List<byte> ls = new List<byte>();
            for (byte i = 0; i < 8; i++)
            {
                int stand = 1 << i;
                int res = stand & j;
                if (res != 0) { ls.Add(i); }
            }
            return ls;
        }
        /// <summary>
        /// 获取bit为1 的所有索引值
        /// </summary>
        /// <param name="j"></param>
        /// <returns></returns>
        public static List<byte> GetBits(this ushort j)
        {
            List<byte> ls = new List<byte>();
            for (byte i = 0; i < 16; i++)
            {
                int stand = 1 << i;
                int res = stand & j;
                if (res != 0) { ls.Add(i); }
            }
            return ls;
        }
        /// <summary>
        /// 获取bit为1 的所有索引值
        /// </summary>
        /// <param name="j"></param>
        /// <returns></returns>
        public static List<byte> GetBits(this int j)
        {
            List<byte> ls = new List<byte>();
            for (byte i = 0; i < 32; i++)
            {
                int stand = 1 << i;
                int res = stand & j;
                if (res != 0) { ls.Add(i); }
            }
            return ls;
        }
        /// <summary>
        /// 获取bit为1 的所有索引值
        /// </summary>
        /// <param name="j"></param>
        /// <returns></returns>
        public static List<byte> GetBits(this long j)
        {
            List<byte> ls = new List<byte>();
            for (byte i = 0; i < 64; i++)
            {
                long stand = 1L << i;
                long res = stand & j;
                if (res != 0) { ls.Add(i); }
            }
            return ls;
        }
        /// <summary>
        /// 大小端互换
        /// </summary>
        /// <param name="num"></param>
        /// <param name="Ignore">是否忽略反转</param>
        /// <returns></returns>
        public static ushort ByteReserse(this ushort num, bool Ignore = false)
        {
            if (!Ignore)
            {
                byte[] data = BitConverter.GetBytes(num);
                return BitConverter.ToUInt16(data.Reverse().ToArray(), 0);
            }
            return num;
        }
        /// <summary>
        /// 大小端互换
        /// </summary>
        /// <param name="num"></param>
        /// <param name="Ignore">是否忽略反转</param>
        /// <returns></returns>
        public static short ByteReserse(this short num, bool Ignore = false)
        {
            if (!Ignore)
            {
                byte[] data = BitConverter.GetBytes(num);
                return BitConverter.ToInt16(data.Reverse().ToArray(), 0);
            }
            return num;
        }
        /// <summary>
        /// 大小端互换
        /// </summary>
        /// <param name="num"></param>
        /// <param name="Ignore">是否忽略反转</param>
        /// <returns></returns>
        public static int ByteReserse(this int num, bool Ignore = false)
        {
            if (!Ignore)
            {
                byte[] data = BitConverter.GetBytes(num);
                return BitConverter.ToInt32(data.Reverse().ToArray(), 0);
            }
            return num;
        }
        /// <summary>
        /// 大小端互换
        /// </summary>
        /// <param name="num"></param>
        /// <param name="Ignore">是否忽略反转</param>
        /// <returns></returns>
        public static uint ByteReserse(this uint num, bool Ignore = false)
        {
            if (!Ignore)
            {
                byte[] data = BitConverter.GetBytes(num);
                return BitConverter.ToUInt32(data.Reverse().ToArray(), 0);
            }
            return num;
        }
        /// <summary>
        /// 大小端互换
        /// </summary>
        /// <param name="num"></param>
        /// <param name="Ignore">是否忽略反转</param>
        /// <returns></returns>
        public static long ByteReserse(this long num, bool Ignore = false)
        {
            if (!Ignore)
            {
                byte[] data = BitConverter.GetBytes(num);
                return BitConverter.ToInt64(data.Reverse().ToArray(), 0);
            }
            return num;
        }
        /// <summary>
        /// 大小端互换
        /// </summary>
        /// <param name="num"></param>
        /// <param name="Ignore">是否忽略反转</param>
        /// <returns></returns>
        public static ulong ByteReserse(this ulong num, bool Ignore = false)
        {
            if (!Ignore)
            {
                byte[] data = BitConverter.GetBytes(num);
                return BitConverter.ToUInt64(data.Reverse().ToArray(), 0);
            }
            return num;
        }
        /// <summary>
        /// 大小端互换
        /// </summary>
        /// <param name="num"></param>
        /// <param name="Ignore">是否忽略反转</param>
        /// <returns></returns>
        public static float ByteReserse(this float num, bool Ignore = false)
        {
            if (!Ignore)
            {
                byte[] data = BitConverter.GetBytes(num);
                return BitConverter.ToSingle(data.Reverse().ToArray(), 0);
            }
            return num;
        }
        /// <summary>
        /// 大小端互换
        /// </summary>
        /// <param name="num"></param>
        /// <param name="Ignore">是否忽略反转</param>
        /// <returns></returns>
        public static double ByteReserse(this double num, bool Ignore = false)
        {
            if (!Ignore)
            {
                byte[] data = BitConverter.GetBytes(num);
                return BitConverter.ToDouble(data.Reverse().ToArray(), 0);
            }
            return num;
        }
        /// <summary>
        /// 判定是否小端cpu平台
        /// </summary>
        /// <returns></returns>
        public static bool IsLettleEndingPlatfrom(this object o)
        {
            ushort data = 0xff00;
            return BitConverter.GetBytes(data)[0] == 0;
        }
    }
}
